package top.wenzz.commons.utils;

import com.mysql.jdbc.MysqlDataTruncation;
import org.hibernate.ObjectNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.transaction.TransactionSystemException;
import top.wenzz.commons.exception.NotFindEntityException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.sql.SQLIntegrityConstraintViolationException;

/**
 * 数据异常处理类
 * Created by 钟廷员 on 2016/9/18.
 */
public class ExceptionUtils {
    private static Logger log = LoggerFactory.getLogger(ExceptionUtils.class);

    public static String getExceptionMsg(Exception e) {
        log.debug("系统异常：", e);

        if (e instanceof ConstraintViolationException) {
            ConstraintViolationException cve = (ConstraintViolationException) e;
            for (ConstraintViolation violation : cve.getConstraintViolations()) {
                return violation.getMessageTemplate();
            }
            return "未知异常：事务无法提交";
        } else if(e instanceof TransactionSystemException) {
            Throwable t;
            if((t = getException(e, ConstraintViolationException.class)) != null) {// 校验失败
                ConstraintViolationException cve = (ConstraintViolationException)t;
                for (ConstraintViolation violation : cve.getConstraintViolations()) {
                    return violation.getMessageTemplate();
                }
            }
            return "未知异常：事务无法提交";
        } else if (e instanceof DataIntegrityViolationException) {// 数据完整性异常
            Throwable t;
            if ((t = getException(e, SQLIntegrityConstraintViolationException.class)) != null) {
                String ret = isExistMsg(t, "Duplicate entry");// 数据唯一性异常
                if (ret != null) {
                    ret = ret.replace("Duplicate entry", "重复的数据：");
                    ret = ret.substring(0, ret.lastIndexOf(" for key"));
                    return ret;
                }
                ret = isExistMsg(e, "FOREIGN KEY", "Cannot delete or update a parent row: a foreign key constraint fails");// 外键关联异常
                if (ret != null) {
                    ret = "该数据已被其他表关联，不能删除";
                    return ret;
                }
            } else if ((t = getException(e, MysqlDataTruncation.class)) != null) {
                String ret = isExistMsg(t, "Data too long for column");// 数据唯一性异常
                if (ret != null) {
                    return "数据过长，不能入库";
                }
            }
            return "未知异常：事务无法提交";
        } else if (e instanceof NullPointerException) {// 空指针异常
            return "系统异常：null";
        } else if (e instanceof NumberFormatException) {
            return "数字格式化异常";
        } else if (e instanceof ObjectNotFoundException) {
            return "无法根据ID查询到对应的bean";
        } else if (e instanceof NotFindEntityException) {
            return e.getMessage();
        }

        log.error("系统异常：", e);
        // 未知异常
        return "未知系统异常，请联系管理员";
    }

    private static Throwable getException(Throwable t, Class<?> clazz) {
        if (t == null)
            return null;
        if (clazz.isAssignableFrom(t.getClass()))
            return t;
        else
            return getException(t.getCause(), clazz);
    }

    private static String isExistMsg(Throwable e, String... msg) {
        while (e != null) {
            boolean f = true;
            for (String m : msg) {
                if (!e.getMessage().contains(m)) {
                    f = false;
                    break;
                }
            }
            if (f)
                return e.getMessage();

            e = e.getCause();
        }
        return null;
    }
}
